package org.cleverframe.common.controller;

import java.beans.PropertyEditorSupport;
import java.util.Date;
import java.util.List;

import javax.validation.ConstraintViolationException;
import javax.validation.Validator;

import org.cleverframe.common.spring.SpringBeanNames;
import org.cleverframe.common.utils.DateUtils;
import org.cleverframe.common.utils.IUserUtils;
import org.cleverframe.common.validator.BeanValidatorUtils;
import org.cleverframe.common.vo.AjaxMessage;
import org.cleverframe.modules.sys.SysBeanNames;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

/**
 * SpringMVC实现的控制器基类<br>
 * 1.提供验证功能<br>
 * 2.提供IUserUtils，方便获取当前用户的组织架构信息<br>
 * 
 * @author LiZW
 * @version 2015年5月28日 下午4:38:30
 */
public abstract class BaseController
{
	/** 日志对象 */
	private final static Logger logger = LoggerFactory.getLogger(BaseController.class);

    /** IUserUtils方便获取当前用户的组织架构信息 */
    @Autowired
    @Qualifier(SysBeanNames.UserUtils)
	protected IUserUtils userUtils;
	
	/** 验证Bean实例对象 */
	@Autowired
	@Qualifier(SpringBeanNames.VALIDATOR)
	protected Validator validator;

	/**
	 * 将Spring验证信息放入AjaxMessage对象中<br>
	 * 1.BindingResult中有错误AjaxMessage的Success属性就会被设置成False，Message属性就会设置成“服务端数据验证失败”<br>
	 * 
	 * @param bindingResult Spring验证的错误消息
	 * @param message AjaxMessage对象
	 * @return 验证有错误返回False，无错误返回True
	 */
	protected boolean beanValidator(BindingResult bindingResult, AjaxMessage message)
	{
		if(bindingResult.hasErrors())
		{
		    message.setSuccess(false);
		    message.setMessage("服务端数据验证失败");
			List<FieldError> validError = bindingResult.getFieldErrors();
			for (FieldError fieldError : validError)
			{
				String entityName = fieldError.getObjectName();
				String filed = fieldError.getField();
				String errorMessage = fieldError.getDefaultMessage();
				String code = fieldError.getCode();
				String value = fieldError.getRejectedValue() == null ? "null" : fieldError.getRejectedValue().toString();
				message.addValidMessage(fieldError);
				logger.debug("entityName:" + entityName + 
						" | filed:" + filed + 
						" | errorMessage:" + errorMessage + 
						" | code:" + code + 
						" | value:" + value);
			}
		}
		else
		{
			message.setSuccess(true);
		}
		return !bindingResult.hasErrors();
	}
	
	/**
	 * 服务端参数有效性验证
	 * 
	 * @param object 验证的实体对象
	 * @param groups 验证组
	 * @return 验证成功：返回true 验证失败：将错误信息添加到 Spring的Model中
	 */
	protected boolean beanValidator(Model model, Object object, Class<?>... groups)
	{
		try
		{
			BeanValidatorUtils.validateWithException(validator, object, groups);
		}
		catch (ConstraintViolationException ex)
		{
			List<String> list = BeanValidatorUtils.extractPropertyAndMessageAsList(ex, ": ");
			list.add(0, "数据验证失败：");
			addMessage(model, list.toArray(new String[] {}));
			return false;
		}
		return true;
	}

	/**
	 * 服务端参数有效性验证
	 * 
	 * @param object 验证的实体对象
	 * @param groups 验证组
	 * @return 验证成功：返回true 验证失败：将错误信息添加到 flash message 中
	 */
	protected boolean beanValidator(RedirectAttributes redirectAttributes, Object object, Class<?>... groups)
	{
		try
		{
			BeanValidatorUtils.validateWithException(validator, object, groups);
		}
		catch (ConstraintViolationException ex)
		{
			List<String> list = BeanValidatorUtils.extractPropertyAndMessageAsList(ex, ": ");
			list.add(0, "数据验证失败：");
			addMessage(redirectAttributes, list.toArray(new String[] {}));
			return false;
		}
		return true;
	}

	/**
	 * 添加Model消息
	 * 
	 * @param messages 消息
	 */
	protected void addMessage(Model model, String... messages)
	{
		StringBuilder sb = new StringBuilder();
		for (String message : messages)
		{
			sb.append(message).append(messages.length > 1 ? "<br/>" : "");
		}
		model.addAttribute("message", sb.toString());
	}

	/**
	 * 添加Flash消息
	 * 
	 * @param messages 消息
	 */
	protected void addMessage(RedirectAttributes redirectAttributes, String... messages)
	{
		StringBuilder sb = new StringBuilder();
		for (String message : messages)
		{
			sb.append(message).append(messages.length > 1 ? "<br/>" : "");
		}
		redirectAttributes.addFlashAttribute("message", sb.toString());
	}

	/**
	 * 初始化数据绑定 <br>
	 * 1.将所有传递进来的String进行HTML编码，防止XSS攻击 <br>
	 * 2.将字段中Date类型转换为String类型<br>
	 */
	@InitBinder
    protected void initBinder(WebDataBinder binder)
    {
        // String类型转换，将所有传递进来的String进行HTML编码，防止XSS攻击
        /*
        binder.registerCustomEditor(String.class, new PropertyEditorSupport()
        {
        	@Override
        	public void setAsText(String text)
        	{
        		setValue(text == null ? null : StringEscapeUtils.escapeHtml4(text.trim()));
        	}

        	@Override
        	public String getAsText()
        	{
        		Object value = getValue();
        		return value != null ? value.toString() : "";
        	}
        });
        */
        // Date 类型转换
        binder.registerCustomEditor(Date.class, new PropertyEditorSupport()
        {
            @Override
            public void setAsText(String text)
            {
                setValue(DateUtils.parseDate(text));
            }
        });
    }
}
